package pers.cz.javacvdemo.redis;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.RedisListCommands.Position;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author yiyi.su
 * @version 1.0.0
 * @description ListOp
 * @createTime 2022/8/25
 */
@Slf4j
public class ListOp extends Operation {

	private ListOperations<String, String> list;

	public ListOp(StringRedisTemplate redisTemplate) {
		this.list = redisTemplate.opsForList();
	}

	public <T> T bLPop(String key, long timeout, TimeUnit unit, Class<T> clz) {
		try {
			return deserialize(list.leftPop(key, timeout, unit), clz);
		} catch (Exception e) {
			log.warn("bLPop exception, key={},timeout={},unit={}", key, timeout, unit, e);
		}
		return null;
	}

	public <T> T bRPop(String key, long timeout, TimeUnit unit, Class<T> clz) {
		try {
			return deserialize(list.rightPop(key, timeout, unit), clz);
		} catch (Exception e) {
			log.warn("bRPop exception, key={},timeout={},unit={}", key, timeout, unit, e);
		}
		return null;
	}

	public <T> T bRPopLPush(String sourceKey, String destinationKey, long timeout, TimeUnit unit, Class<T> clz) {
		try {
			return deserialize(list.rightPopAndLeftPush(sourceKey, destinationKey, timeout, unit), clz);
		} catch (Exception e) {
			log.warn("bRPopLPush exception, sourceKey={},destinationKey={},timeout={},unit={}", sourceKey, destinationKey, timeout, unit, e);
		}
		return null;
	}

	public <T> T lIndex(String key, long index, Class<T> clz) {
		try {
			return deserialize(list.index(key, index), clz);
		} catch (Exception e) {
			log.warn("lIndex exception, key={},index={}", key, index, e);
		}
		return null;
	}

	public Long lInsert(String key, Position position, Object pivot, Object value) {
		try {
			if (position == Position.BEFORE) {
				return list.leftPush(key, serialize(pivot), serialize(value));
			}
			return list.rightPush(key, serialize(pivot), serialize(value));
		} catch (Exception e) {
			log.warn("lInsert exception, key={},position={},pivot={},value={}", key, position, pivot, value, e);
		}
		return null;
	}

	public Long lLen(String key) {
		try {
			return list.size(key);
		} catch (Exception e) {
			log.warn("lLen exception, key={}", key, e);
		}
		return null;
	}

	public <T> T lPop(String key, Class<T> clz) {
		try {
			return deserialize(list.leftPop(key), clz);
		} catch (Exception e) {
			log.warn("lPop exception, key={}", key, e);
		}
		return null;
	}

	public Long lPos(String key, Object element) {
		try {
			return list.indexOf(key, serialize(element));
		} catch (Exception e) {
			log.warn("lPos exception, key={},element={}", key, element, e);
		}
		return null;
	}

	public Long lPush(String key, Object... values) {
		try {
			return list.leftPushAll(key, Arrays.stream(values).map(this::serialize).collect(Collectors.toList()));
		} catch (Exception e) {
			log.warn("lPush exception, key={},values={}", key, values, e);
		}
		return null;
	}

	public <T> Long lPush(String key, Collection<T> values) {
		try {
			return list.leftPushAll(key, values.stream().map(this::serialize).collect(Collectors.toList()));
		} catch (Exception e) {
			log.warn("lPush exception, key={},values={}", key, values, e);
		}
		return null;
	}

	public Long lPush(String key, Object value) {
		try {
			return list.leftPush(key, serialize(value));
		} catch (Exception e) {
			log.warn("lPush exception, key={},value={}", key, value, e);
		}
		return null;
	}

	public Long lPushX(String key, Object value) {
		try {
			return list.leftPushIfPresent(key, serialize(value));
		} catch (Exception e) {
			log.warn("lPushX exception, key={},value={}", key, value, e);
		}
		return null;
	}

	public <T> List<T> lRange(String key, long start, long end, Class<T> clz) {
		try {
			List<String> range = list.range(key, start, end);
			if (range == null) {
				return null;
			}
			return range.stream().map(v -> this.deserialize(v, clz)).collect(Collectors.toList());
		} catch (Exception e) {
			log.warn("lRange exception, key={},start={},end={}", key, start, end, e);
		}
		return null;
	}

	public Long lRem(String key, long count, Object value) {
		try {
			return list.remove(key, count, serialize(value));
		} catch (Exception e) {
			log.warn("lRem exception, key={},count={},value={}", key, count, value, e);
		}
		return null;
	}

	public void lSet(String key, long index, Object value) {
		try {
			list.set(key, index, serialize(value));
		} catch (Exception e) {
			log.warn("lSet exception, key={},index={},value={}", key, index, value, e);
		}
	}

	public void lTrim(String key, long start, long end) {
		try {
			list.trim(key, start, end);
		} catch (Exception e) {
			log.warn("lTrim exception, key={},start={},end={}", key, start, end, e);
		}
	}

	public <T> T rPop(String key, Class<T> clz) {
		try {
			return deserialize(list.rightPop(key), clz);
		} catch (Exception e) {
			log.warn("rPop exception, key={}", key, e);
		}
		return null;
	}

	public <T> T rPopLPush(String sourceKey, String destinationKey, Class<T> clz) {
		try {
			return deserialize(list.rightPopAndLeftPush(sourceKey, destinationKey), clz);
		} catch (Exception e) {
			log.warn("rPopLPush exception, sourceKey={},destinationKey={}", sourceKey, destinationKey, e);
		}
		return null;
	}

	public Long rPush(String key, Object value) {
		try {
			return list.rightPush(key, serialize(value));
		} catch (Exception e) {
			log.warn("rPush exception, key={},value={}", key, value, e);
		}
		return null;
	}

	public <T> Long rPush(String key, Collection<T> values) {
		try {
			return list.rightPushAll(key, values.stream().map(this::serialize).collect(Collectors.toList()));
		} catch (Exception e) {
			log.warn("rPush exception, key={},values={}", key, values, e);
		}
		return null;
	}

	public Long rPushX(String key, Object value) {
		try {
			return list.rightPushIfPresent(key, serialize(value));
		} catch (Exception e) {
			log.warn("rPushX exception, key={},value={}", key, value, e);
		}
		return null;
	}

}
